#!/usr/bin/python -S
"""
streams_test.py: Tests for streams.py
"""

__author__ = 'Andy Chu'


import Queue
import unittest
import subprocess
import sys

from torn import base
from torn import child_process
from torn import ioloop
from torn import log as torn_log

import streams  # module under test


class DummyFile(base.EventEmitter):
  EMITS = ['data', 'close']


class ValueStreamTest(unittest.TestCase):

  def testParse(self):
    d = DummyFile()
    v = streams.TnetValueStream(d)

    values = []
    def echo(value):
      values.append(value)

    v.on('chunk', echo)

    # trigger callback
    v.on_read('3:foo,')
    v.on_read('2:ba,')

    v.on_read('1')  # incomplete length
    v.on_read('0:0123456789,')  # complete

    v.on_read('1')  # incomplete length
    v.on_read('0:01234') # incomplete payload
    v.on_read('567')  # incomplete
    v.on_read('89,')  # complete

    v.on_read('2:in')  # incomplete
    v.on_read(',')  # complete

    v.on_read('3:ba')  # incomplete
    v.on_read('z,4:sp')  # completed one, then another incomplete
    v.on_read('am,')  # completed

    v.on_read('3:bar,4:sp')  # complete, incomplete incomplete
    v.on_read('am,')  # completed

    v.on_read('3:bob,5:carol,')  # 2 complete values

    v.on_read('4:dave,5:em')  # another one

    v.on_read('ily,4:fran,6:george,')  # 2 more

    print values
    self.assertEqual(
        [ '3:foo,', '2:ba,', '10:0123456789,', '10:0123456789,', '2:in,',
          '3:baz,', '4:spam,', '3:bar,', '4:spam,', '3:bob,', '5:carol,',
          '4:dave,', '5:emily,', '4:fran,', '6:george,'],
        values)


class DiskThreadTest(unittest.TestCase):

  def testDiskThread(self):
    c = Queue.Queue()
    c.put(('1.txt', 'log line from process 1\n'))
    c.put(('2.txt', 'log line from process 2\n'))
    c.put(streams.SENTINEL)
    d = streams.DiskThread(c, 'tmp')
    d.run()

    # API
    # 'stream' like stderr -- it emits 'data' and 'close' events
    # Line streams can emit 'data', because they're chunks
    # TnetValueStream emits 'value' because they're not serializable!

  def testQueueMultiplexer(self):
    stream1 = DummyFile()
    stream2 = DummyFile()

    # this registers the stream with the thread
    c = Queue.Queue()
    m = streams.QueueMultiplexer(c)
    m.redirect(stream1, 'file.txt')
    m.redirect(stream2, 'file2.txt')
    stream1.emit('data', 's1')
    stream2.emit('data', 's1')
    stream1.emit('close')
    stream2.emit('close')


def echo(chunk):
  print 'C', repr(chunk)
def done():
  print 'DONE'


def echo2(chunk):
  print 'C2', repr(chunk)
def done2():
  print 'DONE 2'


class MultiplexerTest(unittest.TestCase):

  def testMultiplexer(self):
    m = streams.Multiplexer()
    s1 = streams.ChunkStream()
    s2 = streams.ChunkStream()

    m.redirect(s1, 1)
    m.redirect(s2, 2)

    m.on('chunk', echo)
    m.on('close', done)

    s1.emit('chunk', 'one')
    s1.emit('chunk', 'two')
    s2.emit('chunk', 'ONE')
    s1.emit('close')
    s2.emit('chunk', 'TWO')
    s2.emit('close')

  def testDemultiplexer(self):
    muxed = streams.ChunkStream()

    d = streams.Demultiplexer(muxed)
    s1 = streams.ChunkStream()
    s2 = streams.ChunkStream()
    d.redirect(1, s1)
    d.redirect(2, s2)

    s1.on('chunk', echo)
    s1.on('close', done)

    s2.on('chunk', echo2)
    s2.on('close', done2)

    print 'EMITTING'
    muxed.emit('chunk', '1:1#')
    muxed.emit('chunk', '3:foo,')
    muxed.emit('chunk', '1:2#')
    muxed.emit('chunk', '3:bar,')


if __name__ == '__main__':
  unittest.main()
